package listener;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.sql.DataSource;

import tools.Config;

/**
 * Application Lifecycle Listener implementation class ListenerAP
 *
 */
public class ListenerAP extends Thread implements ServletContextListener {
    
	/** Used to stop the listening loop */
	public static boolean running = true;
	
	private DataSource ds;
	private Connection con = null;
	private Statement stmt = null;
	private DatagramSocket socket;
    
    @Override public void run() {
		super.run();
		
		// gets the elements for database manipulation
    	try{
			Context ctx = new InitialContext();
			this.ds = (DataSource) ctx.lookup(Config.ctxLookup);
			this.con = this.ds.getConnection();
			this.stmt = con.createStatement();
    	}
    	catch(Exception e){e.printStackTrace();}
    	
    	// opens the socket on the listening port
    	try{
			this.socket = new DatagramSocket(Config.PORT_LISTEN);
    	}
    	catch(Exception e){e.printStackTrace();return;}
    	
    	while(ListenerAP.running){

			// Reception of message
			String messageReceived = "";
			try {
				byte[] b = new byte[4000];
				DatagramPacket packetReceived = new DatagramPacket(b, b.length);
				// blocking call
				this.socket.receive(packetReceived);
				messageReceived = new String(packetReceived.getData());
				// We display the message received for test purposes
				System.out.println(messageReceived);
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			String[] values = messageReceived.split(";");
			
			// If values length is 7 then its calibration request
			// "RSSI;X;Y;mid;ZZ:ZZ:ZZ:ZZ:ZZ:ZZ;AP:AP:AP:AP:AP:AP;val"
			if(values.length == 7){
				String x = values[1];
				String y = values[2];
				String mid = values[3];
				String mdAddr = values[4]; // Mobile device address, not used for the calibration part ?!?
				String apAddr = values[5];
				String val = values[6];
				
				
				// Insertion in PostgreSQL BDD
				
				try{
					
					/// We get the apId for the insertion into Rssi
					int apId = -1;
					ResultSet rs = stmt.executeQuery("SELECT id, mac_addr FROM AccessPoint");
					while(rs.next()){
						if(rs.getString("mac_addr").equals(apAddr)){
							apId = rs.getInt("id");
							break;
						}					
					}
					
					if(apId == -1){
						stmt.executeUpdate("INSERT INTO AccessPoint (mac_addr) VALUES ("+apAddr+")", new String[] {"id"});
						rs = stmt.getGeneratedKeys();
						if(rs.next())
							apId = rs.getInt(1);
					}
					
					// Insert into Locations
					stmt.executeUpdate("INSERT INTO Location (x, y, map_id) VALUES ("+x+","+y+","+mid+")", new String[] {"id"});
					// We get back the id of the Location just added
					int locId = -1;
					rs = stmt.getGeneratedKeys();
					if(rs.next())
						locId = rs.getInt(1);
					
					// We insert into Rssi
					stmt.executeUpdate("INSERT INTO Rssi (id_loc, id_ap, avg_val) VALUES ("+locId+","+apId+","+Integer.parseInt(val)+")");
					
				}
				catch(Exception e){}
				
			}
			// Else if values length is 4 then its positionning request
			// RSSI;XX:XX:XX:XX:XX:XX;AP:AP:AP:AP:AP:AP;val
			else if(values.length == 4){
				String mdAddr = values[1];
				String apAddr = values[2];
				String val = values[3];
				
				// Put values in the database, similar as above
				try{
					
					/// We get the apId for the insertion into Rssi
					int apId = -1;
					ResultSet rs = stmt.executeQuery("SELECT id, mac_addr FROM AccessPoint");
					while(rs.next()){
						if(rs.getString("mac_addr").equals(apAddr)){
							apId = rs.getInt("id");
							break;
						}					
					}
					
					if(apId == -1){
						stmt.executeUpdate("INSERT INTO AccessPoint (mac_addr) VALUES ("+apAddr+")", new String[] {"id"});
						rs = stmt.getGeneratedKeys();
						if(rs.next())
							apId = rs.getInt(1);
					}
					
					// We insert into TempRssi
					stmt.executeUpdate("INSERT INTO TempRssi (ap_id, client_mac, avg_val) VALUES ("+apId+","+mdAddr+","+Double.parseDouble(val)+")");
					
				}
				catch(Exception e){}
				
			}
		}
		if(con != null){
			try{
				con.close();
			}
			catch(Exception e){}
		}
		
	}

	@Override public void contextInitialized(ServletContextEvent arg0) {
		this.start();

	}
	
	@Override public void contextDestroyed(ServletContextEvent arg0) {
		this.running = false;
		this.interrupt();
		try {
			if(this.socket != null)
				this.socket.close();
		} catch (Exception e) {e.printStackTrace();}
	}
	
}
